package com.hllxd.hism.framework.httprpc.service;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * @author: lixiyong
 * @description:
 * @create: 2020-10-12 15:47
 */
@Slf4j
@Component
public class RestGrpcServiceBuilder implements InitializingBean {

    @Autowired
    private ApplicationContext applicationContext;

    private Map<String, ClazzMethod>  mappingsMap = null;

    public ClazzMethod getClazzMethod(String path) {
        return mappingsMap.get(path);
    }

    public Set<String> getMappingsUri() {
        if(mappingsMap==null) {
            return null;
        }
        return mappingsMap.keySet();
    }

    public static class ClazzMethod {
        public String clazzName;
        public Object clazzObject;
        public Method method;

        @Override
        public String toString() {
            return clazzName+":"+method.getName();
        }
    }

    @Override public void afterPropertiesSet() throws Exception {
        Map<String, Object> beansWithAnnotationMap = applicationContext.getBeansWithAnnotation(PvBeanServiceRel.class);
        for(Map.Entry<String, Object> entry : beansWithAnnotationMap.entrySet()) {
            //获取到实例对象的class信息
            Class<? extends Object> clazz = entry.getValue().getClass();
            PvBeanServiceRel pvService = clazz.getAnnotation(PvBeanServiceRel.class);
            if (pvService == null) {
                log.error("pv is null. {}", entry.getKey());
                continue;
            }
            log.info(entry.getKey() + "-" + JSON.toJSONString(pvService));
            for(String pv: pvService.pvList()){
                if(pv.contains(",")){
                    log.info("pv format is invalid. {}", pv);
                }
                log.info("service name: {}, pv:{}, desc: {}, author: {}.",entry.getKey(), pv, pvService.desc(), pvService.author());
            }
        }
        mappingsMap = requestMappings();
        for(Map.Entry<String, ClazzMethod> entry: mappingsMap.entrySet()) {
            log.info("REST_GRPC: {} - {}", entry.getKey(), entry.getValue().toString());
        }

    }
    static class MethodDef {
        public Method method;
        public String[] mappings;

        public static MethodDef build(Method method, String[] mappings) {
            MethodDef thiz = new MethodDef();
            thiz.method = method;
            thiz.mappings = mappings;
            return thiz;
        }
    }

    private Map<String, ClazzMethod> requestMappings() {
        Map<String, Object> map = applicationContext.getBeansWithAnnotation(RestGrpcService.class);
        Map<String, ClazzMethod> mappingsMap = new LinkedHashMap<String, ClazzMethod>();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            String[] classMappingStrings = getReqMappingValues(value);
            ArrayList<MethodDef> list = new ArrayList<MethodDef>();
            for (Method m : value.getClass().getMethods()) {
                String[] methodStrings = getReqMappingValuesFromMethod(m);
                if (! isEmpty(methodStrings)) {
                    list.add(MethodDef.build(m, methodStrings));
                }
            }
            for (String str : classMappingStrings) {
                for (MethodDef ss : list) {
                    for (String s : ss.mappings) {
                        ClazzMethod clazzMethod = new ClazzMethod();
                        clazzMethod.clazzName = key;
                        clazzMethod.clazzObject = value;
                        clazzMethod.method = ss.method;
                        //  key+":"+method
                        mappingsMap.put(str + s, clazzMethod);
                    }
                }
            }
            log.info("look controller key= {}, v{}", key, value.getClass().getName());

        }
        return mappingsMap;
    }
    private static boolean isEmpty(String[] arr) {
        return (arr==null || arr.length == 0);
    }

    private String[] getReqMappingValues(Object value) {
        //String[] v3 =
        return toNullDefalut(value.getClass().getAnnotation(RestGrpcMapping.class), RestGrpcMapping::value, new String[] {""});
    }

    private String[] getReqMappingValuesFromMethod(Method method) {
//        String[] v3 =
        return toNullDefalut(method.getAnnotation(RestGrpcMapping.class), RestGrpcMapping::value, new String[] {});
    }

    /**
     * @param func s如果不为null,则执行此表达式
     * @param nullDefalut 如果s为null直接返回这个值
     */
    public static <T,R> R toNullDefalut(T t,Function<T, R> func, R nullDefalut){
        if(null == t){
            return nullDefalut;
        }
        return func.apply(t);
    }
}
